/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       weekly_generator.cpp

	$Header: /game/weekly_generator.cpp $

	$NoKeywords: $

 ************************************************************************/
// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "weekly_generator.h"

#include "adv_object_type.h"
#include "adventure_ai.h"
#include "adventure_frame.h"
#include "adventure_map.h"
#include "army.h"
#include "basic_dialog.h"
#include "mouse_event.h"
#include "object_registration.h"
#include "player.h"
#include "random.h"
#include "replace_keywords.h"
#include "simple_dialog.h"

namespace
{
	int const k_current_map_format_version = 2;
	int const k_current_random_map_format_version = 2;
	int const k_current_save_format_version = 1;

	t_register_with_type<t_weekly_generator>
		   k_registration( k_adv_object_weekly_material_generator );
	t_object_registration<t_random_weekly_generator>
		   k_random_registration( k_adv_object_random_weekly_material_generator );


	// Translate t_weekly_generator's map version to
	// t_owned_scriptable_adv_object's map version
	inline int to_base_class_map_format_version( int format_version )
	{
		return format_version;
	}

	// Translate t_random_weekly_generator's map version to
	// t_owned_scriptable_adv_object's map version
	inline int random_to_base_class_map_format_version( int format_version )
	{
		return format_version;
	}

	// Translate t_weekly_generator's save file version to
	// t_owned_scriptable_adv_object's save file version
	inline int to_base_class_save_format_version( int format_version )
	{
		if ( format_version == 0 )
			return 1;
		else 
			return 2;
	}
}

static char const* k_model_name[] =
{ 
	"", 
	"mine.weekly.woodcutters_cottage",
	"mine.weekly.miner's guilds",
	"mine.weekly.crystal pool",
	"mine.weekly.imp pit",
	"mine.weekly.apprentice's lab",
	"mine.weekly.leprechaun"
};

t_weekly_generator::t_weekly_generator( t_material type, t_player_color owner_color )
                  : t_owned_scriptable_adv_object( k_model_name[type] )
{
	set_player_color( owner_color );
	m_production_time = 0;
	reset( type );
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
t_weekly_generator::t_weekly_generator( std::string const& source,
									    t_qualified_adv_object_type const& type )
                  : t_owned_scriptable_adv_object( source )
{
	m_production_time = 0;
	reset( t_material( type.major_subtype() ) );
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
void t_weekly_generator::reset( t_material material )
{
	m_material.material = material;
	m_material.amount = get_production( m_material.material );
	if (m_material.material != k_gold && random(0,1) == 0)
	{
		m_material.amount = 500;
		m_material.material = k_gold;
	}
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
void t_weekly_generator::activate_trigger( t_army* army, t_adv_map_point const& point, 
		                                   t_direction direction, t_adventure_frame* frame )
{
	if (!same_team( army->get_owner(), get_owner()))
	{
		if (army->get_living_hero_count() == 0)
		{
			if (army->is_human())
			{
				ok_dialog( get_text( "no_heroes" ), true );
			}
			return;
		}
		set_owner( army->get_owner_number() );
	}

	// check if we're now unflagged
	if (get_owner() == 0)
		return;
	if (m_production_time == 0)
		get_owner()->gain( m_material.material, m_material.amount );

	if (army->get_owner() != NULL && !army->get_owner()->is_computer())
	{
		std::string		text;
		std::string		name = get_name();
		std::string		production;
		t_basic_dialog* dialog = new t_basic_dialog;

		frame->update();
		if ( is_ally( army->get_owner(), get_owner() ) )
		{
			text = get_text("refused_ally");
		}
		else if (m_production_time == 0)
		{
			dialog->add_material( m_material.material, m_material.amount );
			text = get_text( "initial" );
		}
		else
		{
			text = get_text( "empty" );
		}

		text = replace_keywords( text, m_material.amount, m_material.material );
		text = replace_keywords( text, "%object_name", name );
		dialog->set_text( text );
		dialog->add_ok_button();
		dialog->set_title( get_name() );
		dialog->open( get_dialog_bottom( point ), true, k_align_bottom );
		dialog->run_modal();
	}
	if (m_production_time == 0)
		m_production_time = 7;
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
void t_weekly_generator::right_click( t_mouse_event const& event,
								      t_adventure_frame* adventure_frame )
{
	std::string text = get_text( "help" );

	text = replace_keywords( text, "%object_name", get_name() );
	text = replace_keywords( text, get_production(), get_material() );
	show_popup_text( text, event.screen_point );
}


// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
int t_weekly_generator::get_production( t_material type )
{
	static int const production[] = { 1000, 10, 10, 5, 5, 5, 5 };

	return production[type];
}

void t_weekly_generator::place( t_adventure_map& map, t_adv_map_point const& point )
{
    t_owned_scriptable_adv_object::place( map, point );

    int max;

    if (t_material( get_major_subtype() ) == k_gold )
        max = get_production( k_gold ) / 7;
    else
        max = 75;
    map.add_to_total_income ( max );
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
void t_weekly_generator::process_new_day()
{
	if (m_production_time > 0)
		m_production_time--;
	if (m_production_time == 0 && get_owner_number() >= 0)
	{
		get_owner()->gain( m_material.material, m_material.amount );
		reset( get_material() );
		m_production_time = 7;
	}
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
void t_weekly_generator::set_owner( int player_number )
{
	t_owned_adv_object::set_owner( player_number );
}

// -------------------------------------------------------------------
// Save file version
// -------------------------------------------------------------------
int t_weekly_generator::get_version() const
{
	return k_current_save_format_version;
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
bool t_weekly_generator::read( std::streambuf&						stream, 
						       t_qualified_adv_object_type const&	type,
						       int									version )
{
	t_owned_scriptable_adv_object::read( stream, type, to_base_class_save_format_version( version ) );
	m_production_time = get<t_uint8>( stream );
	return true;
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
bool t_weekly_generator::write( std::streambuf& stream ) const
{
	t_owned_scriptable_adv_object::write( stream );
	put<t_uint8>( stream, m_production_time );
	return true;
}

// -------------------------------------------------------------------
// generator which produces material once per week
// -------------------------------------------------------------------
bool t_weekly_generator::read_from_map( std::streambuf& buffer, t_progress_handler* handler )
{
	int format_version = get< t_uint16 >( buffer );
	if ( format_version < 0 || format_version > k_current_map_format_version )
		return false;

	if (!t_owned_scriptable_adv_object::read_from_map( buffer, handler, to_base_class_map_format_version( format_version )))
		return false;

	return true;
}

float t_weekly_generator::ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const
{
	if (army.get_living_hero_count() == 0)
		return 0.0f;

	t_player* player = army.get_owner();
	t_material_values const& values = player->get_material_values();

	// Value of initial output + 20% for potential future output 
	return values[m_material.material] * m_material.amount * 1.2f *
			ai.scale_for_aggression(player, get_owner());
}

// -------------------------------------------------------------------
// random weekly generator which produces material once per week
// -------------------------------------------------------------------
t_random_weekly_generator::t_random_weekly_generator( std::string const& source )
                         : t_owned_scriptable_adv_object( source )
{
}

// -------------------------------------------------------------------
// random weekly generator which produces material once per week
// -------------------------------------------------------------------
void t_random_weekly_generator::place( t_adventure_map& map, t_adv_map_point const& point )
{
	t_counted_ptr<t_weekly_generator> generator;
	t_material          type;

	type = random( k_wood, k_gems );
	generator = new t_weekly_generator( type, get_player_color() );

	t_owned_scriptable_adv_object::copy_events( *generator, *this );

	generator->place( map, point );
}

// -------------------------------------------------------------------
// random weekly generator which produces material once per week
// -------------------------------------------------------------------
bool t_random_weekly_generator::read_from_map( std::streambuf& buffer, t_progress_handler* handler)
{
	int format_version = get< t_uint16 >( buffer );
	if ( format_version < 0 || format_version > k_current_random_map_format_version )
		return false;

	if (!t_owned_scriptable_adv_object::read_from_map( buffer, handler, random_to_base_class_map_format_version( format_version )))
		return false;

	return true;
}

